﻿using System.Collections.Generic;
using System.Data;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using OpenXmlEasy.Common;

namespace OpenXmlEasy.Word
{
    public partial class WordEasy
    {

        public void InsertTable(DataTable dataTable, DataColumn[] imageColumns = null)
        {
            if (dataTable == null) return;

            InsertTableTitle(++_tableCount, dataTable.TableName);

            if (dataTable.Columns.Count < 20)
            {
                GenerateFromDataTable(dataTable, imageColumns);
            }
            else
            {
                var firstColumns = new List<string>();
                var secondColumns = new List<string>();
                var columns = dataTable.Columns.OfType<DataColumn>().Select(m => m.ColumnName).ToList();
                int headNum = 0, midSubNum = 0, tailNum = 0;
                for (var i = 0; i < columns.Count; i++)
                {
                    var column = columns[i];
                    var temps = column.Split('?');
                    var cs = temps[0].Split('|');
                    firstColumns.Add(cs[0]);
                    secondColumns.Add(cs.Length == 2 ? cs[1] : cs[0]);
                }
                var doubleTitle = columns.Any(m => m.Contains("|"));
                for (var i = 0; i < columns.Count; i++)
                {
                    if (firstColumns[i].Equals(secondColumns[i]) && midSubNum == 0)
                    {
                        headNum++;
                    }
                    else if (firstColumns[i].Equals(secondColumns[i]))
                    {
                        tailNum++;
                    }
                }
                var table1 = dataTable.Copy();
                var table2 = dataTable.Copy();
                if (doubleTitle)
                {
                    midSubNum = columns.Count - headNum - tailNum;
                    var midMainNum = firstColumns.Distinct().Count() - headNum - tailNum;
                    var mainSubLength = midSubNum / midMainNum;
                    var splitNum = (midSubNum + tailNum) / 2;
                    var firstMidNum = (splitNum / mainSubLength) * mainSubLength;
                    for (var i = columns.Count - 1; i > headNum + firstMidNum - 1; i--)
                    {
                        table1.Columns.RemoveAt(i);
                    }
                    for (var i = headNum + firstMidNum - 1; i > headNum - 1; i--)
                    {
                        table2.Columns.RemoveAt(i);
                    }
                }
                else
                {
                    var firstNum = columns.Count / 2;
                    for (var i = columns.Count - 1; i > firstNum - 1; i--)
                    {
                        table1.Columns.RemoveAt(i);
                    }
                    for (var i = firstNum - 1; i > 0; i--)
                    {
                        table2.Columns.RemoveAt(i);
                    }
                }
                GenerateFromDataTable(table1);
                InsertEmptyParagraph();
                InsertContent("接下表");
                InsertEmptyParagraph();
                GenerateFromDataTable(table2);
            }
        }

        #region InsertTableCell

        public void GenerateFromDataTable(DataTable dataTable, DataColumn[] imageColumns = null)
        {
            //first column width
            var maxLength = (from DataRow row in dataTable.Rows
                             select row[0] == null ? 0 : row[0].ToString().Length)
                             .Concat(new[] { 0 })
                             .Max();
            var firstColumnWidth = maxLength * 270 * 1.1;

            //插入表格
            var tb = new Table();

            var tableProperties1 = new TableProperties();
            var tableStyle1 = new TableStyle { Val = "table" };
            var tableWidth1 = new TableWidth { Width = "0", Type = TableWidthUnitValues.Auto };
            var tableLook1 = new TableLook { Val = "04A0", FirstRow = true, LastRow = false, FirstColumn = true, LastColumn = false, NoHorizontalBand = false, NoVerticalBand = true };
            var tableJustification1 = new TableJustification { Val = TableRowAlignmentValues.Center };

            tableProperties1.AppendChild(tableStyle1);
            tableProperties1.AppendChild(tableWidth1);
            tableProperties1.AppendChild(tableLook1);
            tableProperties1.AppendChild(tableJustification1);

            tb.AppendChild(tableProperties1);

            var tg = new TableGrid();

            var firstColumns = new List<string>();
            var secondColumns = new List<string>();
            var columns = dataTable.Columns.OfType<DataColumn>().Select(m => m.ColumnName).ToList();
            var tdcss = new string[columns.Count];
            for (var i = 0; i < columns.Count; i++)
            {
                var column = columns[i];
                var temps = column.Split('?');
                if (temps.Length > 1) tdcss[i] = temps[1];
                var cs = temps[0].Split('|');
                firstColumns.Add(cs[0]);
                secondColumns.Add(cs.Length == 2 ? cs[1] : cs[0]);
            }
            var doubleTitle = columns.Any(m => m.Contains("|"));
            var rowNum = dataTable.Rows.Count;
            var columnNum = dataTable.Columns.Count;
            tb.AppendChild(tg);
            //
            var imageColumnList = new List<DataColumn>();
            if (imageColumns != null)
            {
                imageColumnList.AddRange(imageColumns);
            }
            //Create second row
            var secondRow = new TableRow();
            for (var i = 0; i < columnNum; i++)
            {
                var tag = secondColumns[i];
                if (doubleTitle && tag.Equals(firstColumns[i]))
                {
                    secondRow.AppendChild(CreateCell("", 2, false, 1, "BFBFBF"));
                }
                else
                {
                    secondRow.AppendChild(CreateCell(tag, 1, false, 1, "BFBFBF"));
                }
            }
            //插入firstColumns内容
            if (doubleTitle)
            {
                var firstRow = new TableRow();
                for (var i = 0; i < columnNum; i++)
                {
                    var tag = firstColumns[i];
                    var spanVal = 1;
                    for (var j = i + 1; j < columnNum; j++, i++)
                    {
                        var nextTag = firstColumns[j];
                        if (tag.Equals(nextTag))
                        {
                            spanVal++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    firstRow.AppendChild(spanVal == 1
                                             ? CreateCell(tag, 2, true, 1, "BFBFBF")
                                             : CreateCell(tag, 1, false, spanVal, "BFBFBF"));
                }
                tb.AppendChild(firstRow);
            }
            //Insert Second Row
            tb.AppendChild(secondRow);
            //Insert Data
            for (var i = 0; i < rowNum; i++)
            {
                var row = new TableRow();
                for (var j = 0; j < columnNum; j++)
                {
                    var cell = (dataTable.Rows[i])[j];
                    if (imageColumnList.Contains(dataTable.Columns[j]))
                    {
                        row.AppendChild(CreateImageCell(cell == null ? "" : cell.ToString()));
                    }
                    else
                    {
                        var cellText = cell == null ? "" : cell.ToString();
                        if (tdcss[j] == "AllRowSpan" && i == 0)
                        {
                            var newCell = CreateCell(cellText, rowNum);
                            row.AppendChild(newCell);
                        }
                        else if (tdcss[j] == "AllRowSpan" && i != 0)
                        {
                            var newCell = CreateCell(cellText, rowNum, false);
                            row.AppendChild(newCell);
                        }
                        else if (tdcss[j] != "AllRowSpan")
                        {
                            row.AppendChild(CreateCell(cellText));
                        }
                    }
                }
                tb.AppendChild(row);
            }
            _body.Append(new OpenXmlElement[] { tb });

            //tb.GetFirstChild<TableGrid>().GetFirstChild<GridColumn>().Width
            //    = firstColumnWidth.ToString(CultureInfo.InvariantCulture);
        }

        private TableCell CreateCell(string text, int verticalMerge = 1, bool isVerticalMergeStart = true, int span = 1, string fillColor = null)
        {
            var temp = text.Split('?');
            var isVerticalMerge = temp.Length > 1 && temp[1].Contains("RowSpan");
            var isVerticalMergeRestart = temp.Length > 1 && temp[1].Contains("RowSpan") && temp[1].Contains("=");

            text = temp[0];

            var tableCell1 = new TableCell();

            var tableCellProperties1 = new TableCellProperties();
            var tableCellWidth1 = new TableCellWidth { Width = "1704", Type = TableWidthUnitValues.Dxa };
            var tableCellVerticalAlignment = new TableCellVerticalAlignment() { Val = TableVerticalAlignmentValues.Center };


            tableCellProperties1.AppendChild(tableCellWidth1);
            tableCellProperties1.AppendChild(tableCellVerticalAlignment);

            if (fillColor != null)
            {
                var shading1 = new Shading { Val = ShadingPatternValues.Clear, Color = "auto", Fill = fillColor };
                tableCellProperties1.AppendChild(shading1);
            }

            var paragraph1 = new Paragraph { RsidParagraphAddition = "00F0501A", RsidParagraphProperties = "00F0501A", RsidRunAdditionDefault = "00F0501A" };

            var paragraphProperties1 = new ParagraphProperties();
            var justification1 = new Justification { Val = JustificationValues.Center };

            var paragraphMarkRunProperties1 = new ParagraphMarkRunProperties();
            var fontSize1 = new FontSize { Val = "18" };
            var fontSizeComplexScript1 = new FontSizeComplexScript { Val = "18" };

            if (fillColor != null)
            {
                var bold1 = new Bold();
                paragraphMarkRunProperties1.AppendChild(bold1);
            }
            paragraphMarkRunProperties1.AppendChild(fontSize1);
            paragraphMarkRunProperties1.AppendChild(fontSizeComplexScript1);

            paragraphProperties1.AppendChild(paragraphMarkRunProperties1);
            paragraphProperties1.AppendChild(justification1);
            if (isVerticalMerge)
            {
                if (isVerticalMergeRestart)
                {
                    var verticalMerge1 = new VerticalMerge { Val = MergedCellValues.Restart };
                    tableCellProperties1.AppendChild(verticalMerge1);
                }
                else
                {
                    var verticalMerge1 = new VerticalMerge();
                    tableCellProperties1.AppendChild(verticalMerge1);
                }
            }
            if (verticalMerge > 1)
            {
                if (isVerticalMergeStart)
                {
                    var verticalMerge1 = new VerticalMerge { Val = MergedCellValues.Restart };
                    tableCellProperties1.AppendChild(verticalMerge1);
                }
                else
                {
                    var verticalMerge1 = new VerticalMerge();
                    tableCellProperties1.AppendChild(verticalMerge1);
                }
            }
            if (span > 1)
            {
                var gridSpan1 = new GridSpan { Val = span };
                paragraphProperties1.AppendChild(gridSpan1);
            }

            var run1 = new Run();

            var runProperties1 = new RunProperties();
            var runFonts1 = new RunFonts { Ascii = "宋体", HighAnsi = "宋体" };
            var fontSize2 = new FontSize { Val = "18" };
            var fontSizeComplexScript2 = new FontSizeComplexScript { Val = "18" };

            if (fillColor != null)
            {
                var bold1 = new Bold();
                runProperties1.AppendChild(bold1);
            }
            runProperties1.AppendChild(runFonts1);
            runProperties1.AppendChild(fontSize2);
            runProperties1.AppendChild(fontSizeComplexScript2);
            var text1 = new Text { Text = text ?? "" };

            run1.AppendChild(runProperties1);
            run1.AppendChild(text1);

            paragraph1.AppendChild(paragraphProperties1);
            paragraph1.AppendChild(run1);

            tableCell1.AppendChild(tableCellProperties1);
            tableCell1.AppendChild(paragraph1);

            return tableCell1;
        }

        private TableCell CreateImageCell(string imageBase64)
        {
            var htmlHelper = new HtmlHelper();
            var img = htmlHelper.GetImageFromBase64String(imageBase64);
            if (img == null)
            {
                return CreateCell("");
            }
            var mainPart = _doc.MainDocumentPart;
            var imagePart = mainPart.AddImagePart(ImagePartType.Png);
            using (var ms = new MemoryStream())
            {
                img.Save(ms, ImageFormat.Png);
                ms.Position = 0;
                imagePart.FeedData(ms);
            }

            var currId = _elementId++;
            var relationshipId = mainPart.GetIdOfPart(imagePart);

            var tableCell1 = new TableCell();
            {
                var tableCellProperties1 = new TableCellProperties();
                {
                    var tableCellWidth1 = new TableCellWidth() { Width = "2840", Type = TableWidthUnitValues.Dxa };

                    tableCellProperties1.Append(tableCellWidth1);
                }
                Paragraph paragraph1 = new Paragraph() { RsidParagraphAddition = "009F4C84", RsidParagraphProperties = "003B7865", RsidRunAdditionDefault = "003B7865" };
                {
                    Run run1 = new Run();
                    {
                        RunProperties runProperties1 = new RunProperties();
                        NoProof noProof1 = new NoProof();

                        runProperties1.Append(noProof1);

                        Drawing drawing1 = new Drawing();

                        DocumentFormat.OpenXml.Drawing.Wordprocessing.Inline inline1 = new DocumentFormat.OpenXml.Drawing.Wordprocessing.Inline() { DistanceFromTop = (UInt32Value)0U, DistanceFromBottom = (UInt32Value)0U, DistanceFromLeft = (UInt32Value)0U, DistanceFromRight = (UInt32Value)0U, AnchorId = "30868324", EditId = "3361D398" };
                        DocumentFormat.OpenXml.Drawing.Wordprocessing.Extent extent1 = new DocumentFormat.OpenXml.Drawing.Wordprocessing.Extent() { Cx = 952500L, Cy = 190500L };
                        DocumentFormat.OpenXml.Drawing.Wordprocessing.EffectExtent effectExtent1 = new DocumentFormat.OpenXml.Drawing.Wordprocessing.EffectExtent() { LeftEdge = 0L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L };
                        DocumentFormat.OpenXml.Drawing.Wordprocessing.DocProperties docProperties1 = new DocumentFormat.OpenXml.Drawing.Wordprocessing.DocProperties() { Id = (UInt32Value)2U, Name = "图片 2", Description = "C:\\Users\\taomiao\\Desktop\\test.bmp" };

                        DocumentFormat.OpenXml.Drawing.Wordprocessing.NonVisualGraphicFrameDrawingProperties nonVisualGraphicFrameDrawingProperties1 = new DocumentFormat.OpenXml.Drawing.Wordprocessing.NonVisualGraphicFrameDrawingProperties();

                        DocumentFormat.OpenXml.Drawing.GraphicFrameLocks graphicFrameLocks1 = new DocumentFormat.OpenXml.Drawing.GraphicFrameLocks() { NoChangeAspect = true };
                        graphicFrameLocks1.AddNamespaceDeclaration("a", "http://schemas.openxmlformats.org/drawingml/2006/main");

                        nonVisualGraphicFrameDrawingProperties1.Append(graphicFrameLocks1);

                        DocumentFormat.OpenXml.Drawing.Graphic graphic1 = new DocumentFormat.OpenXml.Drawing.Graphic();
                        graphic1.AddNamespaceDeclaration("a", "http://schemas.openxmlformats.org/drawingml/2006/main");

                        DocumentFormat.OpenXml.Drawing.GraphicData graphicData1 = new DocumentFormat.OpenXml.Drawing.GraphicData() { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" };

                        DocumentFormat.OpenXml.Drawing.Pictures.Picture picture1 = new DocumentFormat.OpenXml.Drawing.Pictures.Picture();
                        picture1.AddNamespaceDeclaration("pic", "http://schemas.openxmlformats.org/drawingml/2006/picture");

                        DocumentFormat.OpenXml.Drawing.Pictures.NonVisualPictureProperties nonVisualPictureProperties1 = new DocumentFormat.OpenXml.Drawing.Pictures.NonVisualPictureProperties();
                        DocumentFormat.OpenXml.Drawing.Pictures.NonVisualDrawingProperties nonVisualDrawingProperties1 = new DocumentFormat.OpenXml.Drawing.Pictures.NonVisualDrawingProperties() { Id = (UInt32Value)0U, Name = "Picture 1", Description = "C:\\Users\\taomiao\\Desktop\\test.bmp" };

                        DocumentFormat.OpenXml.Drawing.Pictures.NonVisualPictureDrawingProperties nonVisualPictureDrawingProperties1 = new DocumentFormat.OpenXml.Drawing.Pictures.NonVisualPictureDrawingProperties();
                        DocumentFormat.OpenXml.Drawing.PictureLocks pictureLocks1 = new DocumentFormat.OpenXml.Drawing.PictureLocks() { NoChangeAspect = true, NoChangeArrowheads = true };

                        nonVisualPictureDrawingProperties1.Append(pictureLocks1);

                        nonVisualPictureProperties1.Append(nonVisualDrawingProperties1);
                        nonVisualPictureProperties1.Append(nonVisualPictureDrawingProperties1);

                        DocumentFormat.OpenXml.Drawing.Pictures.BlipFill blipFill1 = new DocumentFormat.OpenXml.Drawing.Pictures.BlipFill();

                        DocumentFormat.OpenXml.Drawing.Blip blip1 = new DocumentFormat.OpenXml.Drawing.Blip() { Embed = relationshipId };

                        DocumentFormat.OpenXml.Drawing.BlipExtensionList blipExtensionList1 = new DocumentFormat.OpenXml.Drawing.BlipExtensionList();

                        DocumentFormat.OpenXml.Drawing.BlipExtension blipExtension1 = new DocumentFormat.OpenXml.Drawing.BlipExtension() { Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}" };

                        DocumentFormat.OpenXml.Office2010.Drawing.UseLocalDpi useLocalDpi1 = new DocumentFormat.OpenXml.Office2010.Drawing.UseLocalDpi() { Val = false };
                        useLocalDpi1.AddNamespaceDeclaration("a14", "http://schemas.microsoft.com/office/drawing/2010/main");

                        blipExtension1.Append(useLocalDpi1);

                        blipExtensionList1.Append(blipExtension1);

                        blip1.Append(blipExtensionList1);
                        DocumentFormat.OpenXml.Drawing.SourceRectangle sourceRectangle1 = new DocumentFormat.OpenXml.Drawing.SourceRectangle();

                        DocumentFormat.OpenXml.Drawing.Stretch stretch1 = new DocumentFormat.OpenXml.Drawing.Stretch();
                        DocumentFormat.OpenXml.Drawing.FillRectangle fillRectangle1 = new DocumentFormat.OpenXml.Drawing.FillRectangle();

                        stretch1.Append(fillRectangle1);

                        blipFill1.Append(blip1);
                        blipFill1.Append(sourceRectangle1);
                        blipFill1.Append(stretch1);

                        DocumentFormat.OpenXml.Drawing.Pictures.ShapeProperties shapeProperties1 = new DocumentFormat.OpenXml.Drawing.Pictures.ShapeProperties() { BlackWhiteMode = DocumentFormat.OpenXml.Drawing.BlackWhiteModeValues.Auto };

                        DocumentFormat.OpenXml.Drawing.Transform2D transform2D1 = new DocumentFormat.OpenXml.Drawing.Transform2D();
                        DocumentFormat.OpenXml.Drawing.Offset offset1 = new DocumentFormat.OpenXml.Drawing.Offset() { X = 0L, Y = 0L };
                        DocumentFormat.OpenXml.Drawing.Extents extents1 = new DocumentFormat.OpenXml.Drawing.Extents() { Cx = 952500L, Cy = 190500L };

                        transform2D1.Append(offset1);
                        transform2D1.Append(extents1);

                        DocumentFormat.OpenXml.Drawing.PresetGeometry presetGeometry1 = new DocumentFormat.OpenXml.Drawing.PresetGeometry() { Preset = DocumentFormat.OpenXml.Drawing.ShapeTypeValues.Rectangle };
                        DocumentFormat.OpenXml.Drawing.AdjustValueList adjustValueList1 = new DocumentFormat.OpenXml.Drawing.AdjustValueList();

                        presetGeometry1.Append(adjustValueList1);
                        DocumentFormat.OpenXml.Drawing.NoFill noFill1 = new DocumentFormat.OpenXml.Drawing.NoFill();

                        DocumentFormat.OpenXml.Drawing.Outline outline1 = new DocumentFormat.OpenXml.Drawing.Outline();
                        DocumentFormat.OpenXml.Drawing.NoFill noFill2 = new DocumentFormat.OpenXml.Drawing.NoFill();

                        outline1.Append(noFill2);

                        shapeProperties1.Append(transform2D1);
                        shapeProperties1.Append(presetGeometry1);
                        shapeProperties1.Append(noFill1);
                        shapeProperties1.Append(outline1);

                        picture1.Append(nonVisualPictureProperties1);
                        picture1.Append(blipFill1);
                        picture1.Append(shapeProperties1);

                        graphicData1.Append(picture1);

                        graphic1.Append(graphicData1);

                        inline1.Append(extent1);
                        inline1.Append(effectExtent1);
                        inline1.Append(docProperties1);
                        inline1.Append(nonVisualGraphicFrameDrawingProperties1);
                        inline1.Append(graphic1);

                        drawing1.Append(inline1);

                        run1.Append(runProperties1);
                        run1.Append(drawing1);
                    }
                    paragraph1.Append(run1);
                }
                tableCell1.Append(tableCellProperties1);
                tableCell1.Append(paragraph1);
            }
            return tableCell1;
        }

        /// <summary>
        /// 表格标题
        /// </summary>
        /// <param name="tableNum"></param>
        /// <param name="tableName"></param>
        public void InsertTableTitle(int tableNum, string tableName)
        {
            var tableTitle = !string.IsNullOrEmpty(tableName)
                                          ? string.Format("表{0}. {1}\n", tableNum, tableName)
                                          : string.Format("表{0}\n", tableNum);
            var paragraph1 = new Paragraph { RsidParagraphAddition = "00190FDF", RsidParagraphProperties = "006C2136", RsidRunAdditionDefault = "00190FDF" };

            var paragraphProperties1 = new ParagraphProperties();
            var spacingBetweenLines1 = new SpacingBetweenLines { Before = "312", BeforeLines = 100, Line = "360", LineRule = LineSpacingRuleValues.Auto };
            var justification1 = new Justification { Val = JustificationValues.Center };

            var paragraphMarkRunProperties1 = new ParagraphMarkRunProperties();
            var runFonts1 = new RunFonts { Hint = FontTypeHintValues.EastAsia };

            paragraphMarkRunProperties1.AppendChild(runFonts1);

            paragraphProperties1.AppendChild(spacingBetweenLines1);
            paragraphProperties1.AppendChild(justification1);
            paragraphProperties1.AppendChild(paragraphMarkRunProperties1);

            var run1 = new Run();

            var runProperties1 = new RunProperties();
            var runFonts2 = new RunFonts { Hint = FontTypeHintValues.EastAsia };

            runProperties1.AppendChild(runFonts2);
            var text1 = new Text { Text = tableTitle };

            run1.AppendChild(runProperties1);
            run1.AppendChild(text1);

            paragraph1.AppendChild(paragraphProperties1);
            paragraph1.AppendChild(run1);
            _body.AppendChild(paragraph1);
        }

        #endregion

    }
}
